/**
 * @file cell.h
 * @brief 
 *  管道中的一个网格的封装类
 * 
 *      包含两个状态，分别是网格起始位置和中间位置的状态
 *      状态包含压强、温度、气体速度、液体速度、气体体积分数
 *      包含一个P-T表的指针，用于查找气体和液体的物性参数
 *      包含一个配置，用于查找管道的物理参数
 * 
 *      能够管理网格的状态，
 *      能够完成状态的更新，
 *      能够计算当前的质量守恒残差、动量守恒残差等
 */
#pragma once

#include <iostream>
#include <cmath>
#include <vector>
#include <cstdio>
#include <map>

#include "PT_table.h"
#include "config.h"
#include "ceres/ceres.h"

// 管道中的一个网格
class Cell {
public:
    int index; // 网格编号
    double pos_begin;   // 网格起始位置
    double pos_mid;     // 网格中间位置
    double sin_theta;   // 管道倾角正弦值（中间位置）

    Cell* left = nullptr; // 左侧网格
    Cell* right = nullptr; // 右侧网格

    PT_Table *pt_table = nullptr; // P-T 表
    Config *config = nullptr; // 配置

    struct Status{
        double P; // 压强 Pa
        double T; // 温度 K
        double v_gas; // 气体速度 m/s
        double v_liq; // 液体速度 m/s
        double alpha_gas; // 气体体积分数
        PT_Entry entry; // P-T 表中的条目
    };
    Status status_begin;        // 网格起始位置的状态
    Status status_mid;          // 网格中间位置的状态
    Status status_begin_next;   // 网格起始位置的下一时刻状态
    Status status_mid_next;     // 网格中间位置的下一时刻状态
    void apply_next_status();   // 将下一时刻状态应用到当前状态
    void update_next_status();  // 将当前状态应用到下一时刻状态
    void update_status_mid_next(); // 更新网格中间位置的下一时刻状态

    double psi_gas; // 液体汽化率 kg/(m^3*s)

    // 更新网格的温度
    void update_T_to_table( map<double, double> &T_gas,
                            map<double, double> &T_liq);
    void update_T_from_table(   map<double, double> &T_gas,
                                map<double, double> &T_liq);
    void update_all_to_table(   map<double, double> &map_v_gas,
                                map<double, double> &map_v_liq,
                                map<double, double> &map_alpha_gas);
    void update_all_from_table( map<double, double> &map_v_gas,
                                map<double, double> &map_v_liq,
                                map<double, double> &map_alpha_gas);

    // 更新Status中的entry
    void update_entry(Status& entry);

    // 假设入口处气液同速，使用入口定流值，更新气液占比
    void update_entrance_alpha(Status &status);

    // 通用守恒残差
    double get_gas_mass_residual();
    double get_liq_mass_residual();
    double get_gas_momentum_residual();
    double get_liq_momentum_residual();
    
    // 计算入口定流残差
    double get_gas_inlet_residual();
    double get_liq_inlet_residual();

    // 计算出口定压残差
    double get_outlet_P_residual();


};